package com.alameda.common.aop;

import com.alameda.common.annotation.DataScope;
import com.alameda.common.base.constant.DataPermTypeConstant;
import com.alameda.common.base.constant.RoleConstant;
import com.alameda.common.exception.BusinessException;
import com.alameda.common.utils.ThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 数据隔离aop
 *
 * @author Lv
 * @date 2024/4/9
 */
@Slf4j
@Aspect
@Component
public class CustomDataPermAop {
    /**
     * 定义线程池
     */
    public final static ThreadLocal<List<String>> THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.alameda.common.annotation.DataScope)")
    public void dataPermPointCut() {

    }

    /**
     * 前置处理
     *
     * @param joinPoint 切点对象
     */
    @Around(value = "dataPermPointCut()")
    public Object dataPerm(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 获取注解标注的方法
        DataScope dataScope = method.getAnnotation(DataScope.class);
        if (dataScope != null) {
            List<String> dataPerms = Arrays.asList(dataScope.type());
            List<String> sqlList = new ArrayList<>();
            String userId = getUserId();
            // 用户数据权限处理
            if (dataPerms.contains(DataPermTypeConstant.DATA_TYPE_USER) && !RoleConstant.CREATER_ID.equals(userId)) {
                // 普通用户登录 拼接数据权限接口
                /// String sql = "create_id = '" + userId + "'";
                String sql = "create_id = " + userId + " ";
                sqlList.add(sql);
            }
            // 将数据权限的sql放到本地线程中
            THREAD_LOCAL.set(sqlList);
        }

        Object proceed = null;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("数据范围控制aop执行出错", throwable);
            BusinessException.throwException(throwable);
        } finally {
            // 释放内存
            THREAD_LOCAL.remove();
        }
        return proceed;
    }

    /**
     * 获取当前登录用户id
     *
     * @return
     */
    private String getUserId() {
        return String.valueOf(ThreadLocalUtils.getUserId());
    }
}